import * as Cesium from '@cesiumjs';
import {
  czmDefaultOptions,
  g3vDefaultOptions,
  defaultViews
} from "./defaultOptions";
import {viewerUtils, tilesetUtils, layersUtils, imageLayerUtils} from "./viewerUtils";
import {
  utils as globeUtils
} from "./globe";

(0, function() {
  //Rectangle(west, south, east, north)
  let rectangle = Cesium.Rectangle.fromDegrees(19, -2, -162, 70);
  rectangle = defaultViews.global.china.rectangle;

  Cesium.Camera.DEFAULT_VIEW_RECTANGLE = rectangle
})();

class G3V {
  constructor(vm, czmOptions, g3vOptions) {
    this.czmOptions = {
      ...czmDefaultOptions,
      ...czmOptions
    };
    this.g3vOptions = {
      ...g3vDefaultOptions,
      ...g3vOptions
    };
    this._viewer = null; //defineProperty
    console.log("G3V constructor!")
  }

  create(container, czmOptions, g3vOptions) {
    if (this.viewer) {
      console.error("viewer is created!")
      return;
    }
    this.czmOptions = {
      ...this.czmOptions,
      ...czmOptions
    };
    this.g3vOptions = {
      ...this.g3vOptions,
      ...g3vOptions
    };

    const baseImageryProviderOptions = this.czmOptions.imageryProvider;

    this.baseImageryLayerOptions = (baseImageryProviderOptions && baseImageryProviderOptions.options)
    this.czmOptions.imageryProvider = imageLayerUtils.createImageProvider(baseImageryProviderOptions)

    if(this.czmOptions.terrainProvider){
      const {type,options} = this.czmOptions.terrainProvider;
      if(type==="default"){
        this.czmOptions.terrainProvider = Cesium.createWorldTerrain(options)
      }
    }

    const viewer = new Cesium.Viewer(container, this.czmOptions);

    //Add basic drag and drop functionality
    viewer.extend(Cesium.viewerDragDropMixin);

    //Show a pop-up alert if we encounter an error when processing a dropped file
    this._dropErrorListener = viewer.dropError.addEventListener(function(dropHandler, name, error) {
      console.error(error);
    }, this);

    this.navigation = viewerUtils.initNavigation(viewer, this.g3vOptions.navigation)

    const scene = viewer.scene;
    const globe = viewer.scene.globe;
    this._viewer = viewer;
    Object.defineProperty(this, "viewer", {
      get() {
        return this._viewer
      }
    })
    Object.defineProperty(this, "scene", {
      get() {
        return scene
      }
    })
    Object.defineProperty(this, "globe", {
      get() {
        return globe
      }
    })

    Object.defineProperty(this, "dataSources", {
      get() {
        return viewer.dataSources
      }
    })
    Object.defineProperty(this, "imageryLayers", {
      get() {
        return viewer.imageryLayers
      }
    })
    Object.defineProperty(this, "layers", {
      get() {
        return new function(){
          this.get = (name)=>{
            return layersUtils.get(viewer,name)
          }
        }
      }
    })
    Object.defineProperty(this, "entities", {
      get() {
        return viewer.entities
      }
    })
    Object.defineProperty(this, "camera", {
      get() {
        return viewer.camera
      }
    })
    Object.defineProperty(this, "primitives", {
      get() {
        return scene.primitives
      }
    })
    Object.defineProperty(this, "groundPrimitives", {
      get() {
        return scene.groundPrimitives
      }
    })

    Object.defineProperty(this, "baseImageLayer", {
      get() {
        return viewer.imageryLayers.get(0)
      }
    })

    viewerUtils.addlayers(viewer, this.g3vOptions.layers||this.g3vOptions.addImageLayers||[]);
    globeUtils.updateGlobeByOptions(globe, this.g3vOptions.globe);

    this.update();

    return viewer
  }

  update() {
    const {
      viewer,
      scene,
      globe,
      czmOptions,
      g3vOptions,
      imageryLayers,
      baseImageLayer,
      baseImageryLayerOptions
    } = this;

    // globe.depthTestAgainstTerrain = !!this.g3vOptions.depthTestAgainstTerrain;

    imageLayerUtils.updateImageLayerByOptions(baseImageLayer, baseImageryLayerOptions)
    imageLayerUtils.updateImageLayerTitle(baseImageLayer, baseImageryLayerOptions)

    if (g3vOptions.hideLayers) {
      imageryLayers._layers.forEach(e => e.show = false);
    }
  }

  destroy() {
    this._dropErrorListener && this.viewer.dropError.removeEventListener(this._dropErrorListener, this);
    this._dropErrorListener = null;
    this.navigation && this.navigation.destroy()
    this.navigation = null;
    this.viewer && this.viewer.destroy()
    this._viewer = null;
  }

  getLayer(name){
    return layersUtils.get(this.viewer,name)
  }

  addTileset(lyrDefine,readyCallback){
    const {
      viewer
    } = this;
    return tilesetUtils.add(viewer,lyrDefine,readyCallback);
  }
}

export default G3V;
